package com.jy.datapipeline.export.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.jy.datapipeline.common.config.DBMetaDataConfig;
import com.jy.datapipeline.export.service.DataSourceInfoService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

@Getter
@Slf4j
@RestController
@RequestMapping(value = "/metadata/")
public class MetaDataController {
    @Autowired
    private DataSourceInfoService dataSourceInfoService;

    @RequestMapping(value = "/getSchemas", method = RequestMethod.GET)
    @ResponseBody
    public Object getSchemas(@RequestParam(value = "dataSourceId",required = true) String dataSourceId) {
        Map<String, Object> map=new HashMap<>();
        try {
            DruidDataSource ds= DBMetaDataConfig.dataSourceMap.get(dataSourceId);
            List<String> schema=this.getAllSchemas(ds);
            map.put("data",schema);
            map.put("status", true);
        } catch (Exception e) {

            log.error("getSchemas ---err=",e);
            map.put("status", false);
            map.put("data",new ArrayList<>());
        }
        return map;
    }

    @RequestMapping(value = "/getTables", method = RequestMethod.GET)
    @ResponseBody
    public Object getTables(
        @RequestParam(value = "dataSourceId",required = true) String dataSourceId,
        @RequestParam(value = "schema",required = true) String schema,
        @RequestParam(value = "tblName",required = true) String tblName,
        @RequestParam(value = "searchType",required = true) int searchType,//0 模糊搜索，1 精确搜索
        @RequestParam(value = "startIndex",required = true) int startIndex, Integer endIndex) {
        Map<String, Object> map=new HashMap<>();
        try {
            return dataSourceInfoService.findTables(dataSourceId, schema, tblName, searchType, startIndex, endIndex, map);
        } catch (Exception e) {
            log.error("getTabless ---err=",e);
            map.put("status", false);
            map.put("data",new ArrayList<>());
        }
        return map;
    }

    @RequestMapping(value = "/getTableByColumn", method = RequestMethod.GET)
    @ResponseBody
    public Object getTableByColumn(
        @RequestParam(value = "dataSourceId",required = true) String dataSourceId,
        @RequestParam(value = "tableName",required = true) String tableName,
        @RequestParam(value = "schema",required = true) String schema
        ) {
        Map<String, Object> map=new HashMap<>();
        try {
            DruidDataSource ds= DBMetaDataConfig.dataSourceMap.get(dataSourceId);
            List<Map<String,Object>> list=this.getTableByColumn(ds,tableName,schema);

            map.put("data",list);
            map.put("status", true);
        } catch (Exception e) {

            log.error("getTableByColumn ---err=",e);
            map.put("status", false);
            map.put("data",new ArrayList<>());
        }
        return map;
    }

    public List<Map<String,Object>> getTableByColumn(DruidDataSource dataSource,String tableName,String schema) throws SQLException {
        try (Connection connection = dataSource.getConnection()) {
            connection.setAutoCommit(false);
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet rs = metaData.getColumns(null, schema, tableName, "%");
            //ArrayList<String> list = new ArrayList<>(20);
            List<Map<String,Object>> list=new ArrayList<>(20);
            while (rs.next()) {
                Map<String,Object> map=new HashMap<>();
                String column=rs.getString("COLUMN_NAME");
                if(!column.equals("polarSeqRowid")){
                    map.put("column",column);
                    map.put("column_type",rs.getString("TYPE_NAME"));
                }
                if (MapUtils.isNotEmpty(map)) {
                    list.add(map);
                }
            }
            connection.commit();
            rs.close();
            connection.close();

            return this.toUpperCaseColumns(list);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 字段转为我大写返回
     * @param tableColumns
     * @return
     */
    private List<Map<String, Object>> toUpperCaseColumns(List<Map<String,Object>> tableColumns) {
        List<Map<String, Object>> tableUpperCaseColumns = new ArrayList<>();
        Map<String, Object> tableUpperCaseColumn;
        for (Map<String, Object> tableColumn : tableColumns) {
            Set<String> keySet = tableColumn.keySet();
            tableUpperCaseColumn = new HashMap<>();
            for (String key : keySet) {
                tableUpperCaseColumn.put(key, tableColumn.get(key).toString().toUpperCase(Locale.ROOT));
            }
            tableUpperCaseColumns.add(tableUpperCaseColumn);
        }
        return tableUpperCaseColumns;
    }

    public List<String> getAllSchemas(DruidDataSource dataSource) throws SQLException {
        try (Connection connection = dataSource.getConnection()) {
            connection.setAutoCommit(false);
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet schemas = metaData.getSchemas();
            ArrayList<String> list = new ArrayList<>(20);
            while (schemas.next()) {
                String schema = schemas.getString(1);
                    list.add(schema);
            }
            connection.commit();
            schemas.close();
            connection.close();
            return this.toUpperCaseSchemas(list);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 模式名转为大写
     * @param allSchemas
     * @return
     */
    private List<String> toUpperCaseSchemas(List<String> allSchemas) {
        List<String> allUpperCaseSchemas = new ArrayList<>();
        for (String allSchema : allSchemas) {
            allUpperCaseSchemas.add(allSchema.toUpperCase(Locale.ROOT));
        }
        return allUpperCaseSchemas;
    }
}
